package thread;

//  死锁
//  1. 可重入锁 一个线程一把锁
//  2. 两个线程, 两把锁
public class demo18_synchronized {

    private  static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();

        /**
         * 查看 jconsole 可以看到, 当前线程状态是: BLOCKED, 说明当前状态属于锁竞争, 锁冲突的状态.
         */
//        Thread t1 = new Thread(() -> {
//            synchronized (lock1) {
//                System.out.println("t1 获取到 lock1");
//                sleep(1000);
//                synchronized (lock2) {
//                    System.out.println("t1 获取到 lock2");
//                }
//            }
//        });
//
//        Thread t2 = new Thread(() -> {
//           synchronized (lock2) {
//               System.out.println("t2 获取到 lock2");
//               sleep(1000);
//               synchronized (lock1) {
//                   System.out.println("t2 获取到 lock1");
//               }
//           }
//        });
//
//        t1.start();
//        t2.start();

        /**
         * 如何避免死锁
         */

        // 1. 打破请求和保持, 代码中避免出现 "锁嵌套" 的情况
//        Thread t1 = new Thread(() -> {
//            synchronized (lock1) {
//                System.out.println("t1 获取到 lock1");
//                sleep(1000);
//            }
//            synchronized (lock2) {
//                System.out.println("t1 获取到 lock2");
//            }
//        });
//
//        Thread t2 = new Thread(() -> {
//            synchronized (lock2) {
//                System.out.println("t2 获取到 lock2");
//                sleep(1000);
//            }
//            synchronized (lock1) {
//                System.out.println("t2 获取到 lock1");
//            }
//        });
//
//        t1.start();
//        t2.start();

        // 2. 打破循环等待, 约定加锁的顺序, 把锁按照从小到大的顺序加锁
        Thread t1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("t1 获取到 lock1");
                sleep(1000);
            }
            synchronized (lock2) {
                System.out.println("t1 获取到 lock2");
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("t2 获取到 lock2");
                sleep(1000);
            }
            synchronized (lock2) {
                System.out.println("t2 获取到 lock1");
            }
        });

        t1.start();
        t2.start();
    }
}
